package com.zues.haikangtempdemo.service;

import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.zues.haikangtempdemo.CommonMethod.osSelect;
import com.zues.haikangtempdemo.config.HCNetSDK;
import com.zues.haikangtempdemo.entity.DeviceBean;
import org.springframework.stereotype.Service;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Date;
import java.util.List;

/**
 * 实时数据读取-备用
 */
@Service
public class ThermometryServiceImplBack {

    static HCNetSDK hCNetSDK = null;

    static int lUserID = -1;

    /**
     * 原版测试
     */
    public void getOldTherm(String ipAddr, int port, String user, String psw) {
        if (hCNetSDK == null) {
            if (!createSDKInstance()) {
                System.out.println("Load SDK fail");
                return;
            }
        }
        //linux系统建议调用以下接口加载组件库
        if (osSelect.isLinux()) {
            HCNetSDK.BYTE_ARRAY ptrByteArray1 = new HCNetSDK.BYTE_ARRAY(256);
            HCNetSDK.BYTE_ARRAY ptrByteArray2 = new HCNetSDK.BYTE_ARRAY(256);
            //这里是库的绝对路径，请根据实际情况修改，注意改路径必须有访问权限
//            String strPath1 = System.getProperty("user.dir") + "/lib/libcrypto.so.1.1";
//            String strPath2 = System.getProperty("user.dir") + "/lib/libssl.so.1.1";
            String strPath1 = "/hkdll/linuxx64/HC/hkdllcrypto.so.1.1";
            String strPath2 = "/hkdll/linuxx64/HC/hkdllssl.so.1.1";

            System.arraycopy(strPath1.getBytes(), 0, ptrByteArray1.byValue, 0, strPath1.length());
            ptrByteArray1.write();
            hCNetSDK.NET_DVR_SetSDKInitCfg(3, ptrByteArray1.getPointer());

            System.arraycopy(strPath2.getBytes(), 0, ptrByteArray2.byValue, 0, strPath2.length());
            ptrByteArray2.write();
            hCNetSDK.NET_DVR_SetSDKInitCfg(4, ptrByteArray2.getPointer());

//            String strPathCom = System.getProperty("user.dir") + "/lib/";
            String strPathCom = "/hkdll/linuxx64/HC/";

            HCNetSDK.NET_DVR_LOCAL_SDK_PATH struComPath = new HCNetSDK.NET_DVR_LOCAL_SDK_PATH();
            System.arraycopy(strPathCom.getBytes(), 0, struComPath.sPath, 0, strPathCom.length());
            struComPath.write();
            hCNetSDK.NET_DVR_SetSDKInitCfg(2, struComPath.getPointer());
        }

        /**初始化*/
        hCNetSDK.NET_DVR_Init();
        // 登录设备
        List<DeviceBean> deviceList = new ArrayList<>(3);
//        deviceList.add(new DeviceBean("192.168.1.70",(short) 8000,"admin","a12345678"));
//        deviceList.add(new DeviceBean("192.168.1.81",(short) 8000,"admin","a12345678"));
//        deviceList.add(new DeviceBean("192.168.1.91",(short) 8000,"admin","a12345678"));
        deviceList.add(new DeviceBean("192.168.1.64", (short) 8000, "admin", "a12345678"));
        System.out.println(deviceList.get(0).getIp());

        login_V40("192.168.1.64", (short) 8000, "admin", "woai3hui");  //登录设备

        // 设置实时测温条件
        HCNetSDK.NET_DVR_REALTIME_THERMOMETRY_COND thermometryCond = new HCNetSDK.NET_DVR_REALTIME_THERMOMETRY_COND();
        thermometryCond.dwSize = thermometryCond.size();
        thermometryCond.byRuleID = 6; // 规则 ID
        thermometryCond.dwChan = 2; // 通道号
        thermometryCond.write();

        // 启动远程配置
        int lHandle = hCNetSDK.NET_DVR_StartRemoteConfig(lUserID, 3629
                , thermometryCond.getPointer()
                , thermometryCond.size()
                , new GetThermInfoCallback()
                , new Memory(37));

        if (lHandle < 0) {
            System.out.println("NET_DVR_StartRemoteConfig failed, error code: " + hCNetSDK.NET_DVR_GetLastError());
        } else {
            System.out.println("NET_DVR_StartRemoteConfig is successful!");
        }

        try {
            Thread.sleep(15000); // 等待一段时间
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 停止远程配置
        if (!hCNetSDK.NET_DVR_StopRemoteConfig(lHandle)) {
            System.out.println("NET_DVR_StopRemoteConfig failed, error code: " + hCNetSDK.NET_DVR_GetLastError());
        }

        // 登出设备
        logout(lUserID);
    }


    public void getTherm(String ipAddr, int port, String user, String psw) {
        if (hCNetSDK == null) {
            if (!createSDKInstance()) {
                System.out.println("Load SDK fail");
                return;
            }
        }

        //linux系统建议调用以下接口加载组件库
        if (osSelect.isLinux()) {
            HCNetSDK.BYTE_ARRAY ptrByteArray1 = new HCNetSDK.BYTE_ARRAY(256);
            HCNetSDK.BYTE_ARRAY ptrByteArray2 = new HCNetSDK.BYTE_ARRAY(256);
            //这里是库的绝对路径，请根据实际情况修改，注意改路径必须有访问权限
            String strPath1 = System.getProperty("user.dir") + "/hkdll/linuxx64/HC/hkdllcrypto.so.1.1";
            String strPath2 = System.getProperty("user.dir") + "/hkdll/linuxx64/HC/hkdllssl.so.1.1";
            String strPathCom = System.getProperty("user.dir") + "/hkdll/linuxx64/HC/";


            System.arraycopy(strPath1.getBytes(), 0, ptrByteArray1.byValue, 0, strPath1.length());
            ptrByteArray1.write();
            hCNetSDK.NET_DVR_SetSDKInitCfg(3, ptrByteArray1.getPointer());

            System.arraycopy(strPath2.getBytes(), 0, ptrByteArray2.byValue, 0, strPath2.length());
            ptrByteArray2.write();
            hCNetSDK.NET_DVR_SetSDKInitCfg(4, ptrByteArray2.getPointer());

            HCNetSDK.NET_DVR_LOCAL_SDK_PATH struComPath = new HCNetSDK.NET_DVR_LOCAL_SDK_PATH();
            System.arraycopy(strPathCom.getBytes(), 0, struComPath.sPath, 0, strPathCom.length());
            struComPath.write();
            hCNetSDK.NET_DVR_SetSDKInitCfg(2, struComPath.getPointer());
        }

        /**初始化*/
        hCNetSDK.NET_DVR_Init();

        // 登录设备
        List<DeviceBean> deviceList = new ArrayList<>(3);
//        deviceList.add(new DeviceBean("192.168.1.70",(short) 8000,"admin","a12345678"));
//        deviceList.add(new DeviceBean("192.168.1.64",(short) 8000,"admin","a12345678"));

        login_V40("192.168.1.64", (short) 8000, "admin", "woai3hui");  //登录设备

//        startRealtimeThermometry(lUserID, 2, 2);
        startRealtimeThermometry(lUserID, 3, 2);

        // 登出设备
        logout(lUserID);
    }

    public void startRealtimeThermometry(int lUserID, Integer ruleID, int channel) {
        HCNetSDK.NET_DVR_REALTIME_THERMOMETRY_COND thermometryCond = new HCNetSDK.NET_DVR_REALTIME_THERMOMETRY_COND();
        thermometryCond.dwSize = thermometryCond.size();
        thermometryCond.byRuleID = ruleID.byteValue(); // 规则 ID
        thermometryCond.dwChan = channel; // 通道号
        thermometryCond.write();

        // 启动远程配置
         int lHandle = hCNetSDK.NET_DVR_StartRemoteConfig(lUserID, 3629
                , thermometryCond.getPointer()
                , thermometryCond.size()
                , new GetThermInfoCallback()
                , new Memory(10));

        if (lHandle < 0) {
            System.out.println("NET_DVR_StartRemoteConfig failed, error code: " + hCNetSDK.NET_DVR_GetLastError());
        } else {
            System.out.println("NET_DVR_StartRemoteConfig is successful!");
        }

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        // 停止远程配置
        if (!hCNetSDK.NET_DVR_StopRemoteConfig(lHandle)) {
            System.out.println("NET_DVR_StopRemoteConfig failed, error code: " + hCNetSDK.NET_DVR_GetLastError());
        }
    }


    public static class GetThermInfoCallback implements HCNetSDK.FRemoteConfigCallBack {
        @Override
        public void invoke(int dwType, Pointer pBuffer, int dwBufLen, Pointer pUserData) {
            System.out.println("Return callback invoke");
            System.out.println("-----dwType: " + dwType + "---------dwBufLen: " + dwBufLen);

            if (dwType == 2) {
                HCNetSDK.NET_DVR_THERMOMETRY_UPLOAD struThermometry = new HCNetSDK.NET_DVR_THERMOMETRY_UPLOAD();
                // 截取指定长度的字节数
                int size = struThermometry.size();
                long u = 1;
                System.out.println("--size--");

                System.out.println();
                pBuffer.getString(1);
                byte[] byteArray = pBuffer.getByteArray(u, size);
                ByteBuffer byteBuffer = pBuffer.getByteBuffer(u, size);
                // 将ByteBuffer转换为String
                String string = StandardCharsets.UTF_8.decode(byteBuffer).toString();
                // 输出转换后的字符串
                String base64Str = Base64.getEncoder().encodeToString(byteArray);
                // 当需要还原时
                byte[] originalBytes = Base64.getDecoder().decode(base64Str);

                int n = struThermometry.dwAbsTime;
                HCNetSDK.NET_DVR_POINT_THERM_CFG Temper;
                Temper = struThermometry.struPointThermCfg;
                //float Tem=Temper.fTemperature;

                // 根据 dwType 处理不同的回调类型
                switch (dwType) {
                    case 0:
                        HCNetSDK.REMOTECONFIGSTATUS struCfgStatus = new HCNetSDK.REMOTECONFIGSTATUS();
                        struCfgStatus.write();
                        Pointer pCfgStatus = struCfgStatus.getPointer();
                        pCfgStatus.write(0, pBuffer.getByteArray(0, struCfgStatus.size()), 0, struCfgStatus.size());
                        struCfgStatus.read();
                        int iStatus = 0;
                        for (int i = 0; i < 4; i++) {
                            int iOffset = i * 8;
                            int iByte = struCfgStatus.byStatus[i] & 0xff;
                            iStatus = iStatus + (iByte << iOffset);
                        }
                        System.out.println(iStatus);
                        switch (iStatus) {
                            case 1000: // net_sdk_callback_status_success
                                System.out.println("Real-time thermometry callback success, dwStatus: " + iStatus);
                                break;
                            case 1001:
                                System.out.println("Getting real-time thermometry callback data, dwStatus: " + iStatus);
                                // 假设温度数据在回调数据的某个位置，根据实际情况解析
                                int temperature = pBuffer.getInt(400);
                                System.out.println("实时温度: " + temperature + " 度");
                                break;
                            case 1002:
                                int iErrorCode = 0;
                                for (int i = 0; i < 4; i++) {
                                    int iOffset = i * 8;
                                    int iByte = struCfgStatus.byErrorCode[i] & 0xff;
                                    iErrorCode = iErrorCode + (iByte << iOffset);
                                }
                                System.out.println("Error occurred in real-time thermometry, error code: " + iErrorCode);
                                break;
                        }
                        break;
                    case 2:
                        HCNetSDK.NET_DVR_THERMOMETRY_UPLOAD m_struThermometryInfo = new HCNetSDK.NET_DVR_THERMOMETRY_UPLOAD();
                        m_struThermometryInfo.write();
                        Pointer pInfoV30 = m_struThermometryInfo.getPointer();
                        pInfoV30.write(0, pBuffer.getByteArray(0, m_struThermometryInfo.size()), 0, m_struThermometryInfo.size());
                        m_struThermometryInfo.read();

                        if (m_struThermometryInfo.byRuleCalibType == 0) {
                            System.out.println("点测温信息:" + m_struThermometryInfo.struPointThermCfg.fTemperature);
                        }
                        if (m_struThermometryInfo.byRuleCalibType == 1 || m_struThermometryInfo.byRuleCalibType == 2) {
                            System.out.println("规则为：  " + m_struThermometryInfo.byRuleCalibType);
                            System.out.println("框/线测温信息:fMaxTemperature__" + m_struThermometryInfo.struLinePolygonThermCfg.fMaxTemperature);
                            System.out.println("   fMinTemperature__" + m_struThermometryInfo.struLinePolygonThermCfg.fMinTemperature);
                            System.out.println("  fAverageTemperature__" + m_struThermometryInfo.struLinePolygonThermCfg.fAverageTemperature);
                            System.out.println("   fTemperatureDiff__" + m_struThermometryInfo.struLinePolygonThermCfg.fTemperatureDiff);
                            System.out.println("    fCenterPointTemperature__" + m_struThermometryInfo.fCenterPointTemperature);
                            HCNetSDK.NET_DVR_THERMOMETRY_ALARM struAlarm = new HCNetSDK.NET_DVR_THERMOMETRY_ALARM();
                            if(struAlarm.byAlarmLevel > 0){
                                System.out.println("通道号：" + struAlarm.dwChannel);
                                System.out.println("规则ID：" + struAlarm.byRuleID);
                                System.out.println("报警配置温度：" + struAlarm.fRuleTemperature);
                                System.out.println("报警温度：" + struAlarm.fCurrTemperature);
                            }


                        }


                        break;
                    default:
                        break;

                }
            }
        }
    }

    public static void logout(int lUserID) {
        boolean logoutStatus = hCNetSDK.NET_DVR_Logout(lUserID);
        if (logoutStatus) {
            System.out.println("Logout success");
        } else {
            System.out.println("Logout fail");
        }

        hCNetSDK.NET_DVR_Cleanup();
    }

    public static void login_V40(String ip, short port, String user, String psw) {

        //注册
        HCNetSDK.NET_DVR_USER_LOGIN_INFO m_strLoginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO();//设备登录信息
        HCNetSDK.NET_DVR_DEVICEINFO_V40 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();//设备信息

        String m_sDeviceIP = ip;//设备ip地址
        m_strLoginInfo.sDeviceAddress = new byte[HCNetSDK.NET_DVR_DEV_ADDRESS_MAX_LEN];
        System.arraycopy(m_sDeviceIP.getBytes(), 0, m_strLoginInfo.sDeviceAddress, 0, m_sDeviceIP.length());

        String m_sUsername = user;//设备用户名
        m_strLoginInfo.sUserName = new byte[HCNetSDK.NET_DVR_LOGIN_USERNAME_MAX_LEN];
        System.arraycopy(m_sUsername.getBytes(), 0, m_strLoginInfo.sUserName, 0, m_sUsername.length());

        String m_sPassword = psw;//设备密码
        m_strLoginInfo.sPassword = new byte[HCNetSDK.NET_DVR_LOGIN_PASSWD_MAX_LEN];
        System.arraycopy(m_sPassword.getBytes(), 0, m_strLoginInfo.sPassword, 0, m_sPassword.length());

        m_strLoginInfo.wPort = port;
        m_strLoginInfo.bUseAsynLogin = false; //是否异步登录：0- 否，1- 是
        m_strLoginInfo.byLoginMode = 0;  //ISAPI登录
        m_strLoginInfo.write();
        //启动实时温度检测

        lUserID = hCNetSDK.NET_DVR_Login_V40(m_strLoginInfo, m_strDeviceInfo);
        /*
                hCNetSDK.NET_DVR_StartRemoteConfig(lUserID, dwCommand, Pointer lpInBuffer, int dwInBufferLen, FRemoteConfigCallBack cbStateCallBack, Pointer pUserData);
                LONG lHandle = hCNetSDK.NET_DVR_StartRemoteConfig(lUserID, hCNetSDK.NET_DVR_GET_REALTIME_THERMOMETRY, &struThermCond, sizeof(struThermCond), GetThermInfoCallback, NULL);
        */
        if (lUserID == -1) {
            System.out.println("登录失败，错误码为" + hCNetSDK.NET_DVR_GetLastError());
            return;
        } else {
            System.out.println(ip + ":设备登录成功！");
            return;
        }
    }

    /**
     * 动态库加载
     *
     * @return
     */
    private static boolean createSDKInstance() {
        if (hCNetSDK == null) {
            synchronized (HCNetSDK.class) {
                String strDllPath = "";
                try {
                    if (osSelect.isWindows())
                        //win系统加载库路径
                        strDllPath = System.getProperty("user.dir") + "\\hkdll\\HCNetSDK.dll";
                    else if (osSelect.isLinux())
                        //Linux系统加载库路径
//                        strDllPath = System.getProperty("user.dir") + "/lib/libhcnetsdk.so";
                        strDllPath = "/hkdll/linuxx64/HC/hkdllhcnetsdk.so";

                    hCNetSDK = (HCNetSDK) Native.loadLibrary(strDllPath, HCNetSDK.class);
                } catch (Exception ex) {
                    System.out.println("loadLibrary: " + strDllPath + " Error: " + ex.getMessage());
                    return false;
                }
            }
        }
        return true;
    }
}
